<?php

namespace App\Http\Controllers\VideoApi;

use App\Http\Config\ErrorCode;
use App\Library\UpTools;
use App\Models\video\BroadcasterModel;
use App\Models\video\BroadcasterRelationModel;
use App\Models\video\DataCacheModel;
use App\Models\video\VideoSettingModel;
use App\Models\video\VideoUserModel;
use App\Models\video\UserTokenModel;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class PassportController extends BaseController
{
    public function __construct(Request $request)
    {
        $this->noCheckTokenAction = ['getLoginToken', 'getDecryptMobile', 'getBindMobile', 'getAccountLogin']; //不校验openid
        parent::__construct($request);
    }

    //获取请求token
    public function getLoginToken(Request $request)
    {
        if($this->returnData["code"] !== 0){
            return $this->return_result($this->returnData);
        }
        $type = $request->type ?: "wx";
        if($type == "qq"){
            $field = "qq_app_id as app_id,qq_app_secret as app_secret";
            $wxLoginUrl = "https://api.q.qq.com/sns/jscode2session";
            $platform = "qq";
        }else{
            $field = "app_id,app_secret";
            $wxLoginUrl = "https://api.weixin.qq.com/sns/jscode2session";
            $platform = "wxapp";
        }
        $wxAppConfig = VideoSettingModel::getFields($field, ["mall_id" => $request->mallData["id"]], true, false);
        if(empty($wxAppConfig)){
            return $this->return_result(ErrorCode::code("customized", "小程序未配置"));
        }
        $wxLoginUrl .= "?appid={$wxAppConfig["appId"]}&secret={$wxAppConfig["appSecret"]}&js_code={$request->code}&grant_type=authorization_code";

        $result = UpTools::curl($wxLoginUrl);
        $wxResult = json_decode($result, true);
        if (empty($wxResult)) {
            $this->returnData = ErrorCode::code("customized", "获取session_key及openID时异常，内部错误");
        } else {
            if (!empty($wxResult['errcode'])) {
                $this->returnData = ErrorCode::code("customized", "错误代码：$wxResult[errcode]，消息：$wxResult[errmsg]");
            } else {
                $wxResult["nickname"] = $request->nickname ? $this->emojiFilter($request->nickname) : null;
                $wxResult["avatar"] = $request->avatar ?: null;
                $wxResult["platform"] = $platform;
                $token = UpTools::createGUID(); //生成token
                $data = VideoUserModel::query()->from(VideoUserModel::query()->getModel()->getTable()." as u")
                    ->leftJoin("member as m", function ($join){
                        $join->on("u.openid", "=", "m.up_openid")->where('m.mall_id','=',request()->mallData["id"]);
                    })
                    ->select("u.id", "u.mobile", "m.status", "m.id as memberId", "m.mall_id")
                    ->where(['u.openid' => $wxResult['openid'], "u.mall_id" => request()->mallData["id"], "u.platform" => $platform])
                    ->first();
                if(empty($data)){
                    if($type == "qq") {
                        $userData = $this->createUser($wxResult, $token);
                        $this->returnData["data"] = ["isBindMobile" => true, "token" => $token, "userData" => $userData];
                    }else {
                        DataCacheModel::saveCache(["key" => $token, "value" => $wxResult, "time" => 3300]); //存到缓存和数据库中，下次优先拿缓存
                        $this->returnData["data"] = ["isBindMobile" => false, "token" => $token, "userData" => ""];
                    }
                }else{
                    $data = $data->toArray();
                    if($type != "qq" && !$data["mobile"]){ // 没绑定手机号或者手机号错误
                        $wxResult = array_merge($data, $wxResult);
                        DataCacheModel::saveCache(["key" => $token, "value" => $wxResult, "time" => 3300]); //存到缓存和数据库中，下次优先拿缓存
                        $this->returnData["data"] = ["isBindMobile" => false, "token" => $token, "userData" => ""];
                    }else{ // 已绑定
                        $wxResult["id"] = $data["id"]; //用户ID
                        $wxResult["mobile"] = $data["mobile"]; // 手机
                        if(empty($data["memberId"])){
                            $data = VideoUserModel::query()->from(VideoUserModel::query()->getModel()->getTable()." as u")
                                ->leftJoin("member as m", function ($join){
                                    $join->on("u.mobile", "=", "m.mobile")->where('m.mall_id','=',request()->mallData["id"]);
                                })
                                ->select("m.status", "m.id as memberId")
                                ->where(['u.mobile' => $data["mobile"], "u.mall_id" => request()->mallData["id"]])
                                ->first();
                        }
                        if($data['status'] == '0'){
                            return $this->return_result(ErrorCode::code("customized", "用户已被冻结，请联系管理员"));
                        }
                        $wxResult["memberId"] = $data["memberId"]; // 客户ID
                        $userData = $this->updateUser($wxResult, $token);
                        if(isset($userData["code"])){
                            return $this->return_result($userData);
                        }
                        $this->returnData["data"] = ["isBindMobile" => true, "token" => $token, "userData" => $userData];
                    }
                }
            }
        }
        return $this->return_result($this->returnData);
    }

    // 过滤处理微信昵称中emoji字符
    public function emojiFilter($original_name){
        // Match Emoticons
        $regexEmoticons = '/[\x{1F600}-\x{1F64F}]/u';
        $clean_text = preg_replace($regexEmoticons, '?', $original_name);
        // Match Miscellaneous Symbols and Pictographs
        $regexSymbols = '/[\x{1F300}-\x{1F5FF}]/u';
        $clean_text = preg_replace($regexSymbols, '?', $clean_text);
        // Match Transport And Map Symbols
        $regexTransport = '/[\x{1F680}-\x{1F6FF}]/u';
        $clean_text = preg_replace($regexTransport, '?', $clean_text);
        // Match Miscellaneous Symbols
        $regexMisc = '/[\x{2600}-\x{26FF}]/u';
        $clean_text = preg_replace($regexMisc, '?', $clean_text);
        // Match Dingbats
        $regexDingbats = '/[\x{2700}-\x{27BF}]/u';
        $clean_text = preg_replace($regexDingbats, '?', $clean_text);
        return $clean_text;
    }

    // 解密手机号
    public function getDecryptMobile(Request $request){
        if($this->returnData["code"] !== 0){
            return $this->return_result($this->returnData);
        }
        foreach (["encryptedData", "iv", "code"] as $v) {
            if(empty($request->$v)){
                return $this->return_result(ErrorCode::code("params_not_exist", $v));
            }
        }
        $wxAppConfig = VideoSettingModel::getFields("app_id,app_secret", ["mall_id" => $request->mallData["id"]], true, false);
        if(empty($wxAppConfig)){
            return $this->return_result(ErrorCode::code("customized", "小程序未配置"));
        }
        $wxLoginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={$wxAppConfig["appId"]}&secret={$wxAppConfig["appSecret"]}&js_code={$request->code}&grant_type=authorization_code";
        $result = UpTools::curl($wxLoginUrl);
        $wxResult = json_decode($result, true);
        if (!empty($wxResult['errcode'])) {
            return $this->return_result(ErrorCode::code("customized", "错误代码：$wxResult[errcode]，消息：$wxResult[errmsg]"));
        }
        $aesKey = base64_decode($wxResult["session_key"]);
        if (strlen($request->iv) != 24) {
            return $this->return_result(ErrorCode::code("customized", "iv参数格式错误"));
        }
        $aesIV = base64_decode($request->iv);
        $aesCipher = base64_decode($request->encryptedData);
        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $dataObj = json_decode($result); // 这是个对象，不是数组
        if ($dataObj == NULL) {
            return $this->return_result(ErrorCode::code("customized", "获取手机号失败，请重试"));
        }
        if ($dataObj->watermark->appid != $wxAppConfig["appId"]) {
            return $this->return_result(ErrorCode::code("customized", "获取手机号失败，请重试"));
        }
        $result = json_decode($result, true);
        $this->returnData["data"] = ["mobile" => $result['purePhoneNumber']];
        return $this->return_result($this->returnData);
    }

    // 绑定手机号，创建或者更新用户信息
    public function getBindMobile(Request $request){
        if($this->returnData["code"] !== 0){
            return $this->return_result($this->returnData);
        }
        if(empty($request->token)){
            return $this->return_result(ErrorCode::code("params_not_exist", "token"));
        }
        if(empty($request->mobile)){
            return $this->return_result(ErrorCode::code("params_not_exist", "手机号"));
        }
        $cacheData = DataCacheModel::getValue($request->token);
        if(empty($cacheData)){
            return $this->return_result(ErrorCode::code("token_expire"));
        }
        $cacheData["password"] = $request->password;
        $cacheData["mobile"] = $request->mobile;
        $data = VideoUserModel::from(VideoUserModel::query()->getModel()->getTable()." as u")
            ->leftJoin("member as m", "u.mobile", "=", "m.mobile")
            ->select("u.id", "m.id as memberId", "m.mall_id")
            ->where(['u.mobile' => $cacheData['mobile'], "u.mall_id" => request()->mallData["id"]])
            ->first(); // 需要查询数据库有没有手机号的用户，有手机号就去掉老账号重新绑定
        if(!empty($data["id"])){
            VideoUserModel::doUpdate(["mobile" => null], ['id' => $data['id']]);
        }
        if(empty($data["memberId"]) || $data["mall_id"] != request()->mallData["id"]){
            $data = VideoUserModel::from(VideoUserModel::query()->getModel()->getTable()." as u")
                ->leftJoin("member as m", "u.mobile", "=", "m.mobile")
                ->select("m.id as memberId")
                ->where(['u.mobile' => $cacheData["mobile"], "u.mall_id" => request()->mallData["id"], "m.mall_id" => request()->mallData["id"]])
                ->first();
        }
        $cacheData["memberId"] = $data["memberId"];
        if(!empty($cacheData["id"])){ // 有用户，但没绑定手机号
            if($cacheData['status'] == '0'){
                return $this->return_result(ErrorCode::code("customized", "用户已被冻结，请联系管理员"));
            }
            $userData = $this->updateUser($cacheData, $request->token);
        }else{ // 没有用户，没绑定手机号
            $userData = $this->createUser($cacheData, $request->token);
        }
        if(isset($userData["code"])){
            return $this->return_result($userData);
        }
        $this->returnData["data"] = ["token" => $request->token, "userData" => $userData ? $userData : []];
        DataCacheModel::del($request->token);
        return $this->return_result($this->returnData);
    }

    // 账号密码登录
    public function getAccountLogin(Request $request){
        if($this->returnData["code"] !== 0){
            return $this->return_result($this->returnData);
        }
        if(empty($request->token)){
            return $this->return_result(ErrorCode::code("params_not_exist", "token"));
        }
        if(empty($request->mobile)){
            return $this->return_result(ErrorCode::code("params_not_exist", "手机号账号"));
        }
        if(empty($request->password)){
            return $this->return_result(ErrorCode::code("params_not_exist", "密码"));
        }
        $cacheData = DataCacheModel::getValue($request->token);
        if(empty($cacheData)){
            return $this->return_result(ErrorCode::code("token_expire"));
        }
        $data = VideoUserModel::query()->from(VideoUserModel::query()->getModel()->getTable()." as u")
            ->rightJoin("member as m", "u.mobile", "=", "m.mobile")
            ->select("u.id", "m.password", "m.id as memberId")
            ->where(["m.mall_id" => request()->mallData["id"], "u.mall_id" => request()->mallData["id"]])
            ->where('m.mobile', $request->mobile)
            ->first();
        if(empty($data)){
            return $this->return_result(ErrorCode::code("account_not_exist"));
        }
        if(!Hash::check($request->password, $data['password'])){
            return $this->return_result(ErrorCode::code("customized", "密码不正确"));
        }
        $cacheData["id"] = empty($cacheData["id"]) ? $data["id"] : $cacheData["id"];
        $cacheData["memberId"] = $data["memberId"];
        if(!empty($cacheData["id"])){ // 有用户，但没绑定手机号
            $userData = $this->updateUser($cacheData, $request->token);
        }else{ // 没有用户，没绑定手机号
            $userData = $this->createUser($cacheData, $request->token);
        }
        if(isset($userData["code"])){
            return $this->return_result($userData);
        }
        $this->returnData["data"] = ["token" => $request->token, "userData" => $userData ? $userData : ""];
        DataCacheModel::del($request->token);
        return $this->return_result($this->returnData);
    }

    // 更新用户信息
    public function updateUser($wxResult, $token){
        $userData = [
            'session_key' => $wxResult['session_key'],
            'nickname' => $wxResult['nickname'],
            'avatar' => $wxResult['avatar'],
            'unionid' => isset($wxResult["unionid"]) ? $wxResult["unionid"] : "",
            'openid' => $wxResult['openid'],
            'mobile' => $wxResult["mobile"]
        ];
        $broadcasterData = BroadcasterModel::query()->from(BroadcasterModel::query()->getModel()->getTable()." as b")
            ->leftJoin(BroadcasterRelationModel::query()->getModel()->getTable()." as br", "b.id", "=", "br.broadcaster_id")
            ->select("br.id", "br.user_id")
            ->where(["b.status" => 1, "b.mall_id" => request()->mallData["id"]])
            ->where(function ($query) use($wxResult) {
                $query->Where("br.openid", $wxResult["openid"]);
                if($wxResult["mobile"]){
                    $query->orWhere("br.mobile", $wxResult["mobile"]);
                }
            })->first();
        if(!empty($broadcasterData["id"])){ // 0普通，1是up,
            $userData["user_type"] = 1;
            if(empty($broadcasterData["user_id"]) || $broadcasterData["user_id"] != $wxResult['id'])
                BroadcasterRelationModel::doUpdate(["user_id" => $wxResult["id"], "openid" => $wxResult["openid"], "mobile" => $wxResult["mobile"]], ["id" => $broadcasterData["id"]]);
        }else{
            $userData["user_type"] = 0;
        }
        $result = VideoUserModel::doUpdate($userData, ["id" => $wxResult['id']]);
        if (isset($result['code'])) {
            return $result;
        }
        if(!$result){
            return ErrorCode::code("customized", "更新用户失败");
        }
        if(empty($wxResult["memberId"])){ // 没有客户账号就创建
            $memberId = DB::table("member")->insertGetId([
                "name" => $wxResult["nickname"], "mobile" => $wxResult["mobile"], "password" => !empty($wxResult["password"]) ? bcrypt($wxResult["password"]) : bcrypt("123456a"),
                "status" => 1, "create_time" => Carbon::now(), "active_time" => Carbon::now(), "mall_id" => request()->mallData["id"], "up_openid" => $wxResult["openid"],
                "user_type" => empty($userData["user_type"]) ? 0 : $userData["user_type"]
            ]);
            if($memberId){
                DB::table("member_extend")->insert(['type' => 0, 'source' => "UP主", "avatar" => $wxResult['avatar'], "member_id" => $memberId]);
            }
        }else{
            DB::table("member")->where("id", $wxResult["memberId"])->update(["up_openid" => $wxResult["openid"], "user_type" => empty($userData["user_type"]) ? 0 : $userData["user_type"]]);
        }
        $ip = UpTools::get_client_ip();
        $id = UserTokenModel::add(["time" => time(), "ip" => $ip, "user_id" => $wxResult["id"], "token" => $token, "mall_id" => request()->mallData["id"]]); // 用户每次登录存放请求token
        if (isset($id['code'])) {
            return $id;
        }
        DataCacheModel::saveCache(["key" => "user_login_{$wxResult["id"]}_{$ip}", "value" => $token]); //存到当前用户登录的token
        $data = VideoUserModel::getFields("id,mall_id,nickname,mobile,avatar,balance,amount,user_type", ["id" => $wxResult["id"]], true, false);
        $cacheData = [
            "id" => $wxResult["id"], "openid" => $wxResult["openid"], "userType" => $data["userType"],
            "sessionKey" => $wxResult["session_key"], "mobile" => $data["mobile"], "mallId" => $data["mallId"]
        ];
        Cache::put("upWeb_" . $token, $cacheData, UserTokenModel::$cacheTime); // 登录信息放缓存
        return $data;
    }

    // 创建用户
    public function createUser($wxResult, $token){
        $userData = [
            'session_key' => $wxResult['session_key'],
            'nickname' => $wxResult['nickname'],
            'avatar' => $wxResult['avatar'],
            'unionid' => isset($wxResult["unionid"]) ? $wxResult["unionid"] : "",
            'openid' => $wxResult['openid'],
            'register_time' => time(),
            'platform' => $wxResult["platform"],
            'user_type' => 0,
        ];
        if(!empty($wxResult["mobile"])) {
            $broadcasterData = BroadcasterModel::query()->from(BroadcasterModel::query()->getModel()->getTable() . " as b")
                ->leftJoin(BroadcasterRelationModel::query()->getModel()->getTable() . " as br", "b.id", "=", "br.broadcaster_id")
                ->select("br.id")
                ->where(["b.status" => 1, "b.mall_id" => request()->mallData["id"], "br.mobile" => $wxResult["mobile"]])
                ->first();
            if (!empty($broadcasterData["id"])) { // 0普通，1是up,
                $userData["user_type"] = 1;
            }
            $userData["mobile"] = $wxResult["mobile"];
        }
        $userId = VideoUserModel::add($userData, true);
        if (isset($userId['code'])) {
            return $userId;
        }
        if(!$userId){
            return ErrorCode::code("customized", "创建用户失败");
        }
        if(!empty($broadcasterData["id"])){ // 0普通，1是up,
            BroadcasterRelationModel::doUpdate(["user_id" => $userId, "openid" => $wxResult["openid"], "mobile" => $wxResult["mobile"]], ["id" => $broadcasterData["id"]]);
        }
        if(empty($wxResult["memberId"])){ // 没有客户账号就创建
            $memberId = DB::table("member")->insertGetId([
                "name" => $wxResult["nickname"], "mobile" => !empty($wxResult["mobile"]) ? $wxResult["mobile"] : "", "status" => 1, "create_time" => Carbon::now(),
                "password" => !empty($wxResult["password"]) ? bcrypt($wxResult["password"]) : bcrypt("123456a"), "active_time" => Carbon::now(),
                "mall_id" => request()->mallData["id"], "up_openid" => $wxResult["openid"], "user_type" => $userData["user_type"]
            ]);
            if($memberId){
                DB::table("member_extend")->insert(['type' => 0, 'source' => "UP主", "avatar" => $wxResult['avatar'], "member_id" => $memberId]);
            }
        }else{
            DB::table("member")->where("id", $wxResult["memberId"])->update(["up_openid" => $wxResult["openid"], "user_type" => $userData["user_type"]]);
        }
        $ip = UpTools::get_client_ip();
        $id = UserTokenModel::add(["time" => time(), "ip" => $ip, "user_id" => $userId, "token" => $token, "mall_id" => request()->mallData["id"]]); // 用户每次登录存放请求token
        if (isset($id['code'])) {
            return $id;
        }
        DataCacheModel::saveCache(["key" => "user_login_{$userId}_{$ip}", "value" => $token]); //存到当前用户登录的token
        $data = VideoUserModel::getFields("mall_id,nickname,mobile,avatar,balance,amount,user_type", ["id" => $userId], true, false);
        $cacheData = ["id" => $userId, "openid" => $wxResult["openid"], "sessionKey" => $wxResult["session_key"], "mobile" => $data["mobile"], "mallId" => $data["mallId"], "userType" => $data["userType"]];
        Cache::put("upWeb_" . $token, $cacheData, UserTokenModel::$cacheTime); //登录信息放缓存
        return $data;
    }

    //退出登陆
    public function logout(Request $request){
        if($this->returnData["code"] !== 0){
            return $this->return_result($this->returnData);
        }
        $userId = $this->getTokenVar($request->token, "id");
        UserTokenModel::delByFilter(["token" => $request->token, "mall_id" => $request->mallData["id"]]);
        DataCacheModel::del("user_login_{$userId}_".UpTools::get_client_ip());
        Cache::forget("upWeb_" . $request->token);
        VideoUserModel::doUpdate(["mobile" => null], ['id' => $userId]);// 退出登录去除绑定手机关系，下次可以用新号绑定
        $this->returnData["msg"] = "成功退出登录";
        return $this->return_result($this->returnData);
    }
}
